package api

import (
	"context"
	"fmt"
	"strings"
	"syscall"
	"time"
	"unsafe"

	"github.com/wailsapp/wails/v2/pkg/runtime"
)

const (
	WH_KEYBOARD_LL = 13
	WM_KEYDOWN     = 0x0100
)

type KBDLLHOOKSTRUCT struct {
	VkCode      uint32  // 按下的虚拟键码（Virtual Key Code）
	ScanCode    uint32  // 按下的扫描码（Scan Code）
	Flags       uint32  // 键盘事件的标志位（Flags）
	Time        uint32  // 事件的时间戳（Time Stamp）
	DwExtraInfo uintptr // 额外信息（Extra Information）
}

type InputRecord struct {
	EventType uint16
	Pad_cgo_0 [2]byte
	Event     KeyEventRecord
}

type KeyEventRecord struct {
	KeyDown         int32
	RepeatCount     int16
	VirtualKeyCode  int16
	VirtualScanCode int16
	Char            uint16
	ControlKeyState uint32
}

var (
	user32             = syscall.NewLazyDLL("user32.dll")
	setWindowsHook     = user32.NewProc("SetWindowsHookExW")
	getMessage         = user32.NewProc("GetMessageW")
	callNextHook       = user32.NewProc("CallNextHookEx")
	unhook             = user32.NewProc("UnhookWindowsHookEx")
	getKeyNameText     = user32.NewProc("GetKeyNameTextW")
	loadKeyboardLayout = user32.NewProc("LoadKeyboardLayoutW")
)

var (
	lastInputTime time.Time
	lastKeys      []KeyEventRecord
	lastInputKey  []string
	_ctx          context.Context
)

func StartWinHooks(ctx context.Context) {
	hook, _, _ := setWindowsHook.Call(WH_KEYBOARD_LL, syscall.NewCallback(keyboardCallback), 0, 0)
	_ctx = ctx
	fmt.Println("Listening for keyboard events. Press any key to exit...")

	var msg struct {
		Hwnd    uintptr
		Message uintptr
		Wparam  uintptr
		Lparam  uintptr
		Time    uint32
		Pt      struct {
			X, Y int32
		}
	}
	for {
		ret, _, _ := getMessage.Call(uintptr(unsafe.Pointer(&msg)), 0, 0, 0)
		if ret == 0 {
			break
		}
		callNextHook.Call(hook, msg.Message, msg.Wparam, msg.Lparam)
	}

	unhook.Call(hook)
}

func keyboardCallback(code int, wParam uintptr, lParam uintptr) uintptr {
	if code == 0 && wParam == WM_KEYDOWN {
		kbdStruct := (*KBDLLHOOKSTRUCT)(unsafe.Pointer(lParam))

		// 获取当前按键的信息
		record := (*InputRecord)(unsafe.Pointer(lParam)).Event

		if shouldResetInput(record) {
			lastKeys = nil
			lastInputKey = make([]string, 0)
		}
		// 获取VK Code对应的键盘输入字母
		keyName := make([]uint16, 256)
		getKeyNameText.Call(uintptr(kbdStruct.ScanCode<<16), uintptr(unsafe.Pointer(&keyName[0])), uintptr(len(keyName)))
		vkCodeLetter := syscall.UTF16ToString(keyName)

		// 获取Scan Code对应的键盘输入字母
		scanCode := kbdStruct.ScanCode
		scanCodeLetter := ""
		if scanCode < 128 {
			scanCodeLetter = string(kbdStruct.VkCode)
		}
		fmt.Printf("Key pressed - VK Code:%d,Scan Code:%d, vkCodeLetter:%s , scanCodeLetter:%s\n", kbdStruct.VkCode, scanCode, vkCodeLetter, scanCodeLetter)
		if kbdStruct.VkCode == 13 {
			inputStr := strings.Join(lastInputKey, "")
			lastKeys = nil
			lastInputKey = make([]string, 0)
			fmt.Println(inputStr)
			if inputStr != "" {
				runtime.EventsEmit(_ctx, "scanResult", inputStr)
			}
		} else if kbdStruct.VkCode == 160 {

		} else {
			lastInputKey = append(lastInputKey, vkCodeLetter)
		}
	}
	lastInputTime = time.Now()
	ret, _, _ := callNextHook.Call(0, uintptr(code), wParam, lParam)

	return ret
}

// 判断是否需要重新记录输入内容
func shouldResetInput(record KeyEventRecord) bool {
	// 判断时间间隔是否超过阈值
	if time.Since(lastInputTime) > 50*time.Millisecond {
		fmt.Println("break..................")
		return true
	}

	// 判断是否有组合键按下
	// if record.ControlKeyState != 0 {
	// 	return true
	// }

	// // 判断是否有多个按键同时按下
	// if len(lastKeys) > 0 && record.VirtualKeyCode != lastKeys[len(lastKeys)-1].VirtualKeyCode {
	// 	return true
	// }

	return false
}
